home *** CD-ROM | disk | FTP | other *** search
/ JCSM Shareware Collection 1993 November / JCSM Shareware Collection - 1993-11.iso / cl720 / qbnws15j.lzh / INTRPT.ASM < prev    next >
Assembly Source File  |  1989-03-14  |  15KB  |  366 lines

  1.        TITLE   INTERRUPT - BASCOM software interrupt calling routine
  2.         PAGE    56,132
  3. ;***
  4. ; INTERRUPT - BASCOM software interrupt calling routine
  5. ;
  6. ;       Copyright <C> 1986, 1987 Microsoft Corporation
  7. ;
  8. ;Purpose:
  9. ;   Allows a BASIC program to invoke an interrupt through a CALL statement.
  10. ;
  11. ;   INTERRUPT allows BASIC to set AX,BX,CX,DX,BP,SI,DI, and the flags
  12. ;   before the call.  INTERRUPTX also allows DS and ES to be set.
  13. ;   Both routines will return the values of the registers upon the
  14. ;   completion of a successful call.  If the interrupt could not
  15. ;   be generated (due to a bad interrupt number or an illegal array)
  16. ;   then the interrupt number will be set to -1 to indicate an error.
  17. ;
  18. ;******************************************************************************
  19. ;
  20. ;Note:
  21. ;   The DOSSEG, .MODEL, .CODE, and .DATA? directives used in this program
  22. ;   are part of the simplified segment system of MASM 5.0. If you have
  23. ;   an earlier version of MASM, you must modify the source to define
  24. ;   the segments required by Microsoft high-level languages. These
  25. ;   segments are discussed in Appendix C of "Learning and Using QuickBASIC."
  26. ;
  27.  
  28. ;       Frame structure definition
  29.  
  30. ARG1    =       0AH             ;pointer to first of three arguments
  31. ARG2    =       08H             ;pointer to second of three arguments
  32. ARG3    =       06H             ;pointer to third of three arguments
  33.  
  34. ;       Frame temp variables
  35.  
  36. UCODE_FLGS =    -02H            ;user code flag register value
  37. UCODE_DS =      -04H            ;user code DS register value
  38. REG_NUM =       -06H            ;number of regs used (INTERRUPT=8, INTERRUPTX=10)
  39. INT_ES  =       -08H            ;INT ES register value
  40. INT_DS  =       -0AH            ;INT DS register value
  41. INT_FLGS =      -0CH            ;INT flags register value
  42. INT_DI  =       -0EH            ;INT DI register value  (was -1EH, bug)
  43. INT_SI  =       -10H            ;INT SI register value
  44. INT_BP  =       -12H            ;INT BP register value
  45. INT_DX  =       -14H            ;INT DX register value
  46. INT_CX  =       -16H            ;INT CX register value
  47. INT_BX  =       -18H            ;INT BX register value
  48. INT_AX  =       -1AH            ;INT AX register value
  49. OLD_SI  =       -1CH            ;save old SI for interpreter
  50. OLD_DI  =       -1EH            ;save old DI for interpreter
  51.  
  52. FRM_SIZ =       -1EH            ;negative size of frame temporaries
  53.  
  54. ;       Locations past frame allocation used to recover post-INT BP value.
  55.  
  56. INT_BP_TMP =    -22H            ;temp location for INT BP register value
  57.  
  58. ;***
  59. ; INTERRUPT, and INTERRUPTX - BASCOM software interrupt calling interface
  60. ;
  61. ; Purpose:
  62. ;       To allow a BASIC Compiler program to perform any software
  63. ;       interrupt.  The interrupt is executed with the registers
  64. ;       set to values specified in a register variable.  The post-
  65. ;       interrupt values of the registers are then stored in
  66. ;       another register  RegType[X],
  67. ;                          outreg AS RegType[X])
  68. ;
  69. ; Inputs:
  70. ;       int_no = interrupt number (range 0 to 255) to execute
  71. ;       inreg and outreg are register variables of type RegType[X]
  72. ;       defined as follows;
  73. ;
  74. ; TYPE RegType
  75. ;     ax    AS INTEGER
  76. ;     bx    AS INTEGER
  77. ;     cx    AS INTEGER
  78. ;     dx    AS INTEGER
  79. ;     bp    AS INTEGER
  80. ;     si    AS INTEGER
  81. ;     di    AS INTEGER
  82. ;     flags AS INTEGER
  83. ; END TYPE
  84. ;
  85. ;
  86. ; TYPE RegTypeX
  87. ;     ax    AS INTEGER
  88. ;     bx    AS INTEGER
  89. ;     cx    AS INTEGER
  90. ;     dx    AS INTEGER
  91. ;     bp    AS INTEGER
  92. ;     si    AS INTEGER
  93. ;     di    AS INTEGER
  94. ;     flags AS INTEGER
  95. ;     ds    AS INTEGER
  96. ;     es    AS INTEGER
  97. ; END TYPE
  98. ;
  99. ; Outputs:
  100. ;       If no error:
  101. ;               int_no = unchanged (range 0 to 255)
  102. ;               outreg: This array will be set to the post-interrupt
  103. ;                       register values.  It has the same structure
  104. ;                       as inreg.
  105. ;       If error:
  106. ;               int_no = -1
  107. ;               outreg unchanged.  INT call is not performed.
  108. ;               error occurs:
  109. ;                       first argument not 0 to 255 (2^8-1)
  110. ;                       second or third arguments not  0 to 1048575 (2^20-1)
  111. ;                               (VARPTR will always be in this range)
  112. ;
  113. ; Modifies:
  114. ;       All, except BP, DS, and flags.
  115. ;       Also, possible side effects of INT call.
  116. ;
  117. ; Exceptions:
  118. ;       INT 24H call may result from some INT 21H MS-DOS calls.
  119. ;
  120. ;******************************************************************************
  121. _bss            segment word PUBLIC 'data'
  122. _bss    ends
  123.  
  124. _data           segment word PUBLIC 'data'
  125. _data   ends
  126.  
  127. dgroup  group   _bss, _data
  128.  
  129. Intrpt_TEXT     segment word PUBLIC 'code'
  130.         assume cs:Intrpt_TEXT, ds:dgroup, es:dgroup, ss:dgroup
  131.  
  132.         PUBLIC INTERRUPT
  133. INTERRUPT PROC  FAR
  134.  
  135.         PUSH    BP              ;save BASCOM frame pointer on stack
  136.         MOV     BP,SP           ;establish program frame reference
  137.         ADD     SP,FRM_SIZ      ;allocate working space for frame
  138.         MOV     WORD PTR [BP].REG_NUM,08H ;eight regs used (not DS or ES)
  139.         JMP     SHORT INTERRUPT_COMMON ;jump to common code
  140.  
  141. INTERRUPT ENDP
  142.  
  143.         PUBLIC INTERRUPTX
  144. INTERRUPTX PROC FAR
  145.  
  146.         PUSH    BP              ;save BASCOM frame pointer on stack
  147.         MOV     BP,SP           ;establish program frame reference
  148.         ADD     SP,FRM_SIZ      ;allocate working space for frame
  149.         MOV     WORD PTR [BP].REG_NUM,0AH ;ten regs used (including DS and ES)
  150.  
  151. ;       Save a copy of the processor flags, SI, DI, and DS in the stack frame.
  152.  
  153. INTERRUPT_COMMON:
  154.         MOV     [BP].OLD_SI,SI  ;save old SI for interpreter
  155.         MOV     [BP].OLD_DI,DI  ;save old DI for interpreter
  156.         MOV     [BP].UCODE_DS,DS;save DS for interpreter
  157.         PUSHF                   ;push the flags on the stack
  158.         POP     [BP].UCODE_FLGS ;put value in the stack frame
  159.  
  160. ;       Move eight or ten words (depending if executing INTERRUPT or INTERRUPTX)
  161. ;       of the integer input array from the far pointer computed to the frame.
  162.  
  163.         MOV     SI,[BP].ARG2    ;and array offset - pointer in DS:SI
  164.         LEA     DI,[BP].INT_AX  ;get start of temporary register storage.
  165.         MOV     CX,[BP].REG_NUM ;eight or ten words to move
  166.         CLD                     ;movement is to higher memory
  167.         PUSH    SS
  168.         POP     ES
  169.         REP     MOVSW           ;move the array into the stack frame
  170.  
  171. ;       Save stack frame pointer to recover its value after the INT call.
  172.  
  173.         PUSH    BP              ;saved to first word past the stack frame
  174.  
  175. ;       Create a two-instruction program on the stack to execute the
  176. ;       INT call requested and return with stack cleanup.
  177. ;
  178. ;       INT     XX      (hex: CD XX)
  179. ;       RETF    06      (hex: CA 06 00)
  180. ;
  181. ;       In the case of INT 25 and 26 (which leave a word of flags on the stack)
  182. ;       We generate:
  183. ;
  184. ;       INT     XX      (hex: CD XX)
  185. ;       ADD     SP,2    (hex: 83 C4 02)     ;this trashes ALL math flags incl CF
  186. ;       RETF    08      (hex: CA 08 00)
  187. ;----------debugged--- CHH solution
  188. ;       INT     XX      (hex: CD XX)
  189. ;       inc     sp      (hex: 44)
  190. ;       inc     sp      (hex: 44)
  191. ;       nop             (hex: 90)
  192. ;       RETF    08      (hex: CA 08 00)
  193. ;
  194.         MOV     SI,[BP].ARG1    ;[SI] = ptr to first CALL arg - interrupt #
  195.         MOV     BX,[SI]         ;[BL] = get integer value of INT type
  196.         OR      BH,BH           ;test if in range, 00 to FFH is legal
  197.         JZ      NO_INT_ERROR    ;if not, then error - jump
  198.         JMP     INT_ERROR       ;long jump to error routine
  199. NO_INT_ERROR:
  200.  
  201.         CMP     BL,25H          ;Interrupt 25 request?
  202.         JZ      Int2526         ;Jump if so
  203.         CMP     BL,26H          ;Interrupt 26 request?
  204.         JNZ     IntNorm         ;Jump if other, "normal" interrupt
  205. Int2526:
  206.         MOV     AX,8            ;[AX] = argument of RETF instruction
  207.         PUSH    AX
  208.         MOV     AX,0CA90H       ;[AX] = RETF opcode & NOP
  209.         PUSH    AX
  210.         MOV     AX,04444H       ;[AX] = INC SP, INC SP no trash CY
  211.         PUSH    AX
  212.         JMP     SHORT IntInstruct
  213.  
  214. IntNorm:
  215.         XOR     AX,AX           ;value of second word past frame
  216.         PUSH    AX              ;put on stack - 00 byte of RETF and filler
  217.         MOV     AX,06CAH        ;value of third word past frame
  218.         PUSH    AX              ;put on stack - CA 06 bytes of RETF
  219. IntInstruct:
  220.         MOV     AH,BL           ;move interrupt number to upper byte of AX
  221.         MOV     AL,0CDH         ;value of fourth word past frame
  222.         PUSH    AX              ;put on stack - CD XX bytes of INT XX
  223.  
  224. ;       Push far pointer of return address after the stack program
  225. ;       executes, which is INT_RET in this code segment.
  226.  
  227.         PUSH    CS              ;push current code segment for return segment
  228.         MOV     AX,OFFSET INT_RET ;offset just after stack program call
  229.         PUSH    AX              ;push value for return offset
  230.  
  231. ;       Push far pointer pointer to the start of the stack program.
  232. ;       The stack program will be entered by executing a RETF after the
  233. ;       registers are set up.
  234.  
  235.         PUSH    SS              ;push current stack segment for starting ptr
  236.         MOV     AX,SP           ;get current stack offset
  237.         ADD     AX,6            ;move past the last three stack entries
  238.         PUSH    AX              ;push offset for starting ptr of stack program
  239.  
  240. ;       Move the input array values from the stack to their actual registers.
  241.  
  242.         MOV     AX,[BP].INT_FLGS ;get input flag register value
  243.         AND     AX,0000111111010101B ;mask out undefined 8086 flags
  244.         PUSH    AX              ;push masked flag register value
  245.  
  246.         MOV     AX,[BP].INT_AX  ;set up input AX value
  247.         MOV     BX,[BP].INT_BX  ;set up input BX value
  248.         MOV     CX,[BP].INT_CX  ;set up input CX value
  249.         MOV     DX,[BP].INT_DX  ;set up input DX value
  250.  
  251.         MOV     SI,[BP].INT_SI  ;set up input SI value
  252.         MOV     DI,[BP].INT_DI  ;set up input DI value
  253.  
  254. ;       For DS and ES, leave in the compiler data segment values if:
  255. ;       executing INTERRUPT; or executing INTERRUPTX with array values of -1.
  256.  
  257.         CMP     WORD PTR [BP].REG_NUM,08H ;test if executing INTERRUPT
  258.         JE      INT_ES_DEF      ;if so, then use both default values
  259.  
  260.         CMP     [BP].INT_DS,0FFFFH ;test if default DS to be used
  261.         JE      INT_DS_DEF      ;if so, then leave it unchanged
  262.         MOV     DS,[BP].INT_DS  ;set up input DS value
  263. INT_DS_DEF:
  264.         CMP     [BP].INT_ES,0FFFFH ;test if default ES to be used
  265.         JE      INT_ES_DEF      ;if so, then leave it unchanged
  266.         MOV     ES,[BP].INT_ES  ;set up input ES value
  267. INT_ES_DEF:
  268.  
  269.         MOV     BP,[BP].INT_BP  ;set up input BP value
  270.                                 ;must be last move using BP
  271.  
  272.         POPF                    ;set up input flag register value
  273.  
  274. ;       With all registers set according to the input array, execute the
  275. ;       stack program.
  276. ;
  277. ;       The following RETF pops the last two stack entries, which are
  278. ;       interpreted as a far pointer to the stack program.
  279. ;
  280. ;       The stack program executes the INT XX call which changes the
  281. ;       registers (flags included) to the values to be put into the
  282. ;       output array.
  283. ;
  284. ;       The stack program then executes the RETF 06 instruction which
  285. ;       does two operations.  First, the next two entries on stack are
  286. ;       popped and interpreted as a far ptr return address, which points
  287. ;       the code at INT_RET in this code segment.  Second, the stack
  288. ;       pointer is then adjusted by six bytes to remove the six-byte
  289. ;       program from the stack.
  290.  
  291.         RET                     ;far return to execute stack program, etc.
  292. INT_RET:
  293.  
  294. ;       The stack should now contain only the first entry past the
  295. ;       frame, the value of the stack frame pointer itself.  First
  296. ;       save the BP value from the INT call, then get the old value
  297. ;       to reference the frame.
  298.  
  299.         PUSH    BP              ;save post-INT value of BP
  300.         MOV     BP,SP           ;temporary frame is second word past frame
  301.         MOV     BP,[BP+02H]     ;get real frame reference value
  302.  
  303. ;       Put post-INT value of all registers into the frame variables
  304. ;       to be subsequently written into the output array.
  305.  
  306.         PUSHF                   ;put flags on the stack
  307.         POP     [BP].INT_FLGS   ;put in post-INT flag register value
  308.  
  309.         PUSH    [BP].UCODE_FLGS ;get old copy of flags from frame
  310.         POPF                    ;and restore the old flag values
  311.  
  312.         MOV     [BP].INT_AX,AX  ;put in post-INT AX value
  313.         MOV     [BP].INT_BX,BX  ;put in post-INT BX value
  314.         MOV     [BP].INT_CX,CX  ;put in post-INT CX value
  315.         MOV     [BP].INT_DX,DX  ;put in post-INT DX value
  316.  
  317.         MOV     AX,[BP].INT_BP_TMP ;get post-INT BP value (one entry past frame)
  318.         MOV     [BP].INT_BP,AX  ;put in post-INT BP value
  319.  
  320.         MOV     [BP].INT_SI,SI  ;put in post-INT SI value
  321.         MOV     [BP].INT_DI,DI  ;put in post-INT DI value
  322.  
  323.         MOV     [BP].INT_DS,DS  ;put in post-INT DS value
  324.         MOV     [BP].INT_ES,ES  ;put in post-INT ES value
  325.  
  326. ;       Move frame register values to the output array whose
  327. ;       far pointer is in the frame.
  328.  
  329.         MOV     DS,[BP].UCODE_DS;replace original DS value
  330.  
  331.         LEA     SI,[BP].INT_AX  ;get start of register area in frame
  332.  
  333.         PUSH    DS
  334.         POP     ES
  335.         MOV     DI,[BP].ARG3    ;get output array offset
  336.         MOV     CX,[BP].REG_NUM ;eight or ten words to move
  337.         CLD                     ;movement is toward upper memory
  338.         REP     MOVSW           ;perform the transfer
  339.  
  340. ;       Clean up stack to remove frame.  Remove CALL arguments with RETF.
  341.  
  342.         MOV     SI,[BP].OLD_SI  ;replace old SI for interpreter
  343.         MOV     DI,[BP].OLD_DI  ;replace old DI for interpreter
  344.         MOV     SP,BP           ;deallocate temporary frame variables
  345.         POP     BP              ;return compiler frame pointer
  346.         RET     06              ;remove three CALL arguments and far return
  347.  
  348. ;       If error, then restore DS, set int_no to -1 to report error,
  349. ;       clean up, and exit.
  350.  
  351. INT_ERROR:
  352.         MOV     SI,[BP].ARG1    ;ptr to first CALL arg - interrupt number
  353.         MOV     [SI],0FFFFH     ;set interrupt number to -1 for error
  354.         MOV     SI,[BP].OLD_SI  ;replace old SI for interpreter
  355.         MOV     DI,[BP].OLD_DI  ;replace old DI for interpreter
  356.         MOV     DS,[BP].UCODE_DS;replace original DS value
  357.         MOV     SP,BP           ;deallocate temporary frame variables
  358.         POP     BP              ;return compiler frame pointer
  359.         RET     06              ;remove three CALL arguments and far return
  360.  
  361. INTERRUPTX ENDP
  362.  
  363. Intrpt_TEXT     ends
  364.                 END
  365.  
  366.